#pragma once
#include "connection.hpp"
//对于我们的套接字写事件的关心初始的条件就是就绪的 因此我们初始不可以进行我们的关心
//当用户有数据直接发送 如果发送之后用户仍有数据 我们此时开始对写事件的关心 继续处理
//如果一次已经发送完了 我们取消关心 避免再次进入写事件的处理函数
class channel : public Connection
{
public:
    channel(int sockfd, InetAddr &client)
        : _sockfd(sockfd),
          _client(client)
    {
        SetEvent(EPOLLIN | EPOLLET | EPOLLHUP | EPOLLERR); // 注意我们这里只关心我们的读事件 不关心我们的写事件 因为写事件默认就是就绪的
        SetNoBlock(_sockfd);
    }
    ~channel()
    {
    }
    int GetFd() override
    {
        return _sockfd;
    }
    virtual void RECV() override
    {
        // 我们读 要保证一次读完 因此循环读
        while (true)
        {
            char buffer[1024];
            int n = read(_sockfd, buffer, sizeof(buffer) - 1);
            if (n < 0)
            {
                // 此时我们要进行判断是不是真的出错了还是由于那个
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    // 此时非足阻塞代表数据被读完了
                    LOG(LogLevel::DEBUG) << _sockfd << "已经没有可读数据了";
                    break;
                }
                else if (errno == EINTR)
                {
                    // 被信号中断此时我们继续读
                    LOG(LogLevel::DEBUG) << _sockfd << "被信号中断了";
                    continue;
                }
                else
                {
                    // 此时错误
                    Excepter();
                    return;
                }
            }
            else if (n == 0)
            {
                // 此时客户端关闭链接
                // 我们要做的是进行我们的
                // 关闭我们的文件描述符
                // 以及从我们的reactor移除
                // 文件描述符的管控
                Excepter();
                return;
            }
            else
            {
                buffer[n] = 0;
                LOG(LogLevel::DEBUG) << "本次读取的内容buffer:" << buffer;
                recvbuffer += buffer;
                LOG(LogLevel::DEBUG) << "此时" << _sockfd << "已经读的内容：" << recvbuffer;
            }
        }
        // 下面调用回调函数处理我们得数据
        if (!recvbuffer.empty())
            sendbuffer += _func(recvbuffer);
        LOG(LogLevel::DEBUG) << "send buffer" << sendbuffer;
        if (!sendbuffer.empty())
            SEND();
    }
    virtual void SEND() override
    {
        LOG(LogLevel::DEBUG) << "进入普通套接字的写事件";
        while (true)
        {
            // 默认的写时间是就绪的
            size_t n = send(_sockfd, sendbuffer.c_str(), sizeof(sendbuffer), 0);
            if (n > 0)
            {
                sendbuffer.erase(0, n);
                if (sendbuffer.empty())
                    break;
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                if (errno == EINTR)
                    continue;
                // 这里才是真正的我们出错
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        // 接着进行写时间的关心
        if (sendbuffer.empty())
        {
            // 此时我们要取消对写时间的关心
            // 这里取消的原因是当我们一次处理完后
            // 此时如果我们不取消对写时间的关心
            // 就会造成写时间又就绪了就会再次进入我们发送过程但是此时已经没有发送的数据了
            GetOwner()->EnableReadWrite(_sockfd, true, false);
        }
        else
        {
            // 开启我们对写时间的关心
            GetOwner()->EnableReadWrite(_sockfd, true, true);
        }
    }
    void Excepter() override
    {
        // 普通套接字 我们要进行的就是删除fd在reactor的管理 以及从epoll模型中移除fd
        // 最后关闭我们的fd 防止fd资源泄露
        GetOwner()->DelConnection(_sockfd);
    }
    InetAddr *GetClient() override
    {
        return &_client;
    }

private:
    int _sockfd;
    std::string recvbuffer;
    std::string sendbuffer;
    InetAddr _client;
};
